#include "connectionpool.h"
ConnectionPool::ConnectionPool(QObject *parent)
    : QObject(parent)
{
    m_minCount = 5;
    m_maxCount = 10;
    m_timeOut = 10000; //
    m_maxIdleTime = 25200000; //7个小时

    m_driverType = "QMYSQL";
    m_hostName = "192.168.1.1";
    m_port = 3306;
    m_databaseName = "xxxxx";
    m_userName = "xxxxx";
    m_password = "xxxxx";


    // 初始化池---最小连接数
    for(int i = 0;i<m_minCount;i++){
        addConnection();
    }

    auto recycleFunc = std::function<void ()> ([&]() {
        this->recycleConnection();
    });

    auto pingFunc = std::function<void ()> ([&]() {
        this->pingConnection();
    });

    thr1 = QThread::create(recycleFunc);
    thr2 = QThread::create(pingFunc);
    thr1->start();
    thr2->start();

}


ConnectionPool::~ConnectionPool()
{
    // 释放线程
    thr1->quit();
    thr2->quit();
    thr1->deleteLater();
    thr2->deleteLater();

    foreach (QSqlDatabase *item, m_freeConnection) {
       item->close();
       delete item;
       item = Q_NULLPTR;
    };
    m_freeConnection.clear();
    foreach (QSqlDatabase *item, m_usedConnection) {
       item->close();
       delete item;
       item = Q_NULLPTR;
    };
    m_usedConnection.clear();

    qDebug()<<"ConnectionPool释放了";
}

ConnectionPool *ConnectionPool::getConnectionPool()
{
    static ConnectionPool _instance;
    return &_instance;
}

QSqlDatabase* ConnectionPool::getConnection()
{
    QMutexLocker locker(&m_mutex);

    // 当前连接数总数
    int sum =m_freeConnection.size()+m_usedConnection.size();

    // 如果连接池已经达到最大了，阻塞
    while(sum>= m_maxCount){
        if(m_cond.wait(&m_mutex,m_timeOut)){
            continue;
        }
    }

    // 没有空闲的则创建新的连接
    if(m_freeConnection.size() == 0){
        addConnection();
    }

    // 存在连接---将其转移到忙碌列表并且返回
    QSqlDatabase *conn = m_freeConnection.dequeue();
    m_usedConnection.push_back(conn);
    m_cond.notify_all();
    return conn;
}

// 回收使用的连接，并且放回池中
void ConnectionPool::closeConnection(QSqlDatabase *db)
{
    int index = m_usedConnection.indexOf(db);
    if(index < 0){
        // 拒绝回收野生连接
        qDebug()<< "[SQLPOOL:]" << "can not recycle a wild connection";
        return;
    }
    QSqlDatabase *conn = m_usedConnection.at(index);
    m_usedConnection.removeAt(index);
    if(!conn->isOpen()) conn->open(); //回收前确保连接没有断开
    m_freeConnection.push_back(conn);
}

// 回收多余的空闲连接
void ConnectionPool::recycleConnection()
{
    while(true){
        QThread::msleep(m_maxIdleTime);
        QMutexLocker locker(&m_mutex);
        int sum = m_freeConnection.size()+m_usedConnection.size();
        if(sum >= m_minCount && m_freeConnection.size()>0){
            QSqlDatabase *conn = m_freeConnection.dequeue();
            conn->close();
            delete conn;
            conn = Q_NULLPTR;
            qDebug()<<"recycle a connection, and release it";
        }
    }
}

// 连接保活器,确保服务器重启后，能够重连
void ConnectionPool::pingConnection()
{
    // 每隔10s保活一次
    while(true){
        QThread::msleep(10000);
        QMutexLocker locker(&m_mutex);
        foreach (QSqlDatabase *item, m_freeConnection) {
            if(!item->open()){
                qInfo()<< "[SQLPOOL:]"<<item->lastError().number()<<":"<<item->lastError().text();
            }
        }
    }
}

// 创建新的连接
void ConnectionPool::addConnection()
{
    QString id = QUuid::createUuid().toString().remove("{").remove("}");
    QSqlDatabase *conn = new QSqlDatabase;
    *conn = QSqlDatabase::addDatabase(m_driverType,id);
    conn->setDatabaseName(m_databaseName);
    conn->setHostName(m_hostName);
    conn->setPort(m_port);
    conn->setUserName(m_userName);
    conn->setPassword(m_password);
    m_freeConnection.push_back(conn);
    if(!conn->open()){
        qInfo()<< "[SQLPOOL:]"<<conn->lastError().number()<<":"<<conn->lastError().text();
    }else{
        qInfo()<< "[SQLPOOL:]"<<"create a new connection, connection name is "<<id;
    }
}

